package com.example.monitoring.config;

import com.example.monitoring.service.ConfigurationFileService;
import io.minio.MinioClient;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 监控配置类
 * 
 * @author rsz
 * @since 2024-04-13
 */
@Configuration
public class MonitoringConfig {

    private final MonitoringProperties properties;
    private final ConfigurationFileService configurationFileService;

    public MonitoringConfig(MonitoringProperties properties, ConfigurationFileService configurationFileService) {
        this.properties = properties;
        this.configurationFileService = configurationFileService;
    }

    @Bean
    public CloseableHttpClient httpClient() {
        return HttpClients.createDefault();
    }
    
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        // 首先尝试从配置文件获取最新配置
        MonitoringProperties loadedProperties = configurationFileService.loadConfiguration();
        MonitoringProperties.Middleware.Redis redisProps = null;
        
        if (loadedProperties != null && loadedProperties.getMiddleware() != null && 
            loadedProperties.getMiddleware().getRedis() != null && 
            loadedProperties.getMiddleware().getRedis().isEnabled()) {
            // 使用从配置文件加载的Redis配置
            redisProps = loadedProperties.getMiddleware().getRedis();
            System.out.println("==================== 使用配置文件中的Redis配置 ====================");
        } else if (properties.getMiddleware() != null && properties.getMiddleware().getRedis() != null && 
                   properties.getMiddleware().getRedis().isEnabled()) {
            // 使用注入的Redis配置作为备选
            redisProps = properties.getMiddleware().getRedis();
            System.out.println("==================== 使用注入的Redis配置 ====================");
        } else {
            System.out.println("==================== Redis配置未启用或不可用 ====================");
            return null;
        }

        // 记录Redis配置信息
        System.out.println("Redis Host: " + redisProps.getHost());
        System.out.println("Redis Port: " + redisProps.getPort());
        System.out.println("Redis Password: " + (redisProps.getPassword() != null && !redisProps.getPassword().isEmpty() ? "已设置" : "未设置"));
        System.out.println("========================================================");

        // 创建Redis配置
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(redisProps.getHost());
        config.setPort(redisProps.getPort());

        if (redisProps.getPassword() != null && !redisProps.getPassword().isEmpty()) {
            config.setPassword(redisProps.getPassword());
        }

        // 配置连接池
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(8);
        poolConfig.setMaxIdle(8);
        poolConfig.setMinIdle(0);
        poolConfig.setTestOnBorrow(true);
        poolConfig.setTestOnReturn(true);

        // 使用新的JedisClientConfiguration Builder API
        JedisClientConfiguration clientConfig = ((JedisClientConfigurationBuilder) JedisClientConfiguration.builder()
                .usePooling()
                .poolConfig(poolConfig))
                .connectTimeout(Duration.ofSeconds(5))
                .readTimeout(Duration.ofSeconds(5))
                .build();

        // 创建连接工厂
        JedisConnectionFactory factory = new JedisConnectionFactory(config, clientConfig);
        factory.afterPropertiesSet(); // 初始化连接工厂

        return factory;
    }

    @Bean
    @ConditionalOnProperty(prefix = "monitoring.middleware.elasticsearch", name = "enabled", havingValue = "true")
    public RestHighLevelClient elasticsearchClient() {
        MonitoringProperties.Middleware.Elasticsearch esProps = properties.getMiddleware().getElasticsearch();
        ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo(esProps.getHosts())
                .withBasicAuth(esProps.getUsername(), esProps.getPassword())
                .build();
        return RestClients.create(clientConfiguration).rest();
    }

    @Bean
    @ConditionalOnProperty(prefix = "monitoring.middleware.minio", name = "enabled", havingValue = "true")
    public MinioClient minioClient() {
        MonitoringProperties.Middleware.MinIO minioProps = properties.getMiddleware().getMinio();
        return MinioClient.builder()
                .endpoint(minioProps.getEndpoint())
                .credentials(minioProps.getAccessKey(), minioProps.getSecretKey())
                .build();
    }

    @Bean
    public ThreadPoolTaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(5);
        scheduler.setThreadNamePrefix("monitoring-scheduler-");
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        scheduler.setAwaitTerminationSeconds(60);
        return scheduler;
    }

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("monitoring-executor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}